#pragma once

#include <vector>
#include <list>
#include <memory>
#include <mutex>

class MemoryObject {
public:
    MemoryObject(size_t size = 65536) : m_buffer(size), m_usedSize(0) {}
    MemoryObject(MemoryObject &&other);
    size_t usedSize() const { return m_usedSize; }
    size_t totalSize() const { return m_buffer.size(); }

    std::vector<unsigned char> &buffer() { return m_buffer; }
    unsigned char* data() { return m_buffer.data(); }

    template<typename T>
    T *castTo() {
        return reinterpret_cast<T*>(data());
    }

    bool fill(unsigned char *data, size_t size, size_t offset = 0);

    void setUsedSize(size_t usedSize){
        m_usedSize = usedSize;
    }

private:
    std::vector<unsigned char> m_buffer;
    size_t m_usedSize;
};

class MemoryObjectPool
{
public:
    MemoryObjectPool(size_t count = 1, size_t size = 65535, size_t maxCount = 5);
    static std::unique_ptr<MemoryObject> create(size_t size = 65535);
    static MemoryObjectPool &instance();
    size_t count() const { return m_pool.size(); }

    std::unique_ptr<MemoryObject> take(size_t leastSize = 65535);
    void give(std::unique_ptr<MemoryObject> &&mo);

private:
    std::list<std::unique_ptr<MemoryObject>> m_pool;
    const size_t m_maxCount;
    std::mutex m_mutex;
};
